package com.ly.consumer.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 处理失败消息的交换机和队列
 * （处理消息消费过程中的业务错误，并且重试机制用尽的情况）
 * （和死信队列，有类似之处，但并不一致）
 *
 * 失败处理策略（3）:
 *       RejectAndDontRequeueRecoverer：重试耗尽后，直接 reject，丢弃消息。（默认）
 *       ImmediateRequeueMessageRecoverer：重试耗尽后，返回 nack，消息重新入队
 *       RepublishMessageRecoverer：重试耗尽后，将失败消息投递到指定的交换机，后续人工介入。(推荐)
 *
 *  推荐使用 RepublishMessageRecoverer ，失败后将消息投递到一个指定的，专门存放异常消息的队列，后续由人工集中处理。
 *
 * @author 23087
 */
@Configuration
//@ConditionalOnProperty(prefix = "spring.rabbitmq.listener.simple.retry.enabled", havingValue = "true") // 开启重试
public class ErrorConfiguration {

    /**
     * 定义 错误处理 交换机
     * @return
     */
    @Bean
    public DirectExchange errorMessageExchange() {
        return new DirectExchange("error.direct");
    }

    /**
     * 创建一个 队列
     * @return
     */
    @Bean
    public Queue errorQueue(){
        return new Queue("error.queue",true);
    }

    /**
     * 绑定 错误处理 交换机和队列
     * @param errorQueue
     * @param errorMessageExchange
     * @return
     */
    @Bean
    public Binding errorBinding(Queue errorQueue, DirectExchange errorMessageExchange) {
        return BindingBuilder.bind(errorQueue).to(errorMessageExchange).with("error");
    }

    /**
     * 关联 队列和交换机
     * @param rabbitTemplate
     * @return
     */
    @Bean
    public MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate){
        return new RepublishMessageRecoverer(rabbitTemplate,"error.direct","error");
    }

}
